package service.validation;

import org.springframework.validation.Errors;

import service.configuration.IFieldNumberConfig;
import entities.Status;

public class NumberValidator {
	
	/**
	 * Récupére le nombre contenu dans la chaine de caractère fournit en argument.
	 * 
	 * @param value la valeur du champs à tester
	 * @return le nombre représenté par value
	 */
	private Integer parseNumber(String value) {
		try {
			return Integer.valueOf(value);
		} catch (NumberFormatException e) {
			return null;
		}
	}
	
	/**
	 * Teste si la valeur respecte la valeur minimum spécifiés dans la configuration.
	 * 
	 * @param value la valeur du champs à tester
	 * @param conf la confgiguration du champs de type nombre (number)
	 * @return true si la limite est précisée et respectée, false sinon
	 */
	private boolean exceedLowerLimit(Integer val, IFieldNumberConfig conf) {
		return  conf.getMin() != null && val < conf.getMin();
	}
	
	/**
	 * Teste si la valeur respecte la valeur maximun spécifiés dans la configuration.
	 * 
	 * @param value la valeur du champs à tester
	 * @param conf la confgiguration du champs de type nombre (number)
	 * @return true si la limite est précisée et respectée, false sinon
	 */
	private boolean exceedUpperLimit(Integer val, IFieldNumberConfig conf) {
		return conf.getMax() != null && val > conf.getMax();
	}
	
	/**
	 * Teste la validité de la valeur d'un champs de type nombre (number).
	 * 
	 * @param value la valeur du champs à tester
	 * @param conf la confgiguration du champs de type nombre (number)
	 * @return le status du champs SoftError ou Valid
	 */
	public Status validate(String value, IFieldNumberConfig conf) {
		if (conf == null || value == null) {
			return FieldValidator.statusValid;
		}
		
		Integer integer = parseNumber(value);
		if (integer == null) {
			return FieldValidator.statusError;
		}
		
		if (exceedLowerLimit(integer, conf) || exceedUpperLimit(integer, conf)) {
			return FieldValidator.statusError;
		}
		
		return FieldValidator.statusValid;
	}
	
	/**
	 * Teste la validité de la valeur d'un champs de type nombre (number),
	 * et lie le champs à un message d'erreur en cas d'erreur.
	 * 
	 * @param name le nom du champs, util pour lier un message d'erreur au champs
	 * @param value la valeur du champs à tester
	 * @param conf la confgiguration du champs de type nombre (number)
	 * @param errors mapping permettant de lier erreurs et messages
	 * @return le status du champs SoftError ou Valid
	 */
	public Status validate(String name, String value, IFieldNumberConfig conf, Errors errors) {
		if (conf == null || value == null) {
			return FieldValidator.statusValid;
		}
		
		Integer integer = parseNumber(value);
		if (integer == null) {
			return FieldValidator.statusError;
		}
		
		if (exceedLowerLimit(integer, conf)) {
			errors.rejectValue(name, "error.field.tooshort", new Object[] {new Integer(conf.getMin())}, "");
			return FieldValidator.statusError;
		}
		if (exceedUpperLimit(integer, conf)) {
			errors.rejectValue(name, "error.field.toolong", new Object[] {new Integer(conf.getMax())}, "");
			return FieldValidator.statusError;
		}
		
		return FieldValidator.statusValid;
	}
}
